/*
Autor: Alexander Savochkin, 2010
New BSD License
*/

#pragma once
#include <boost/optional.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace boost::posix_time;
using boost::optional;

#include "IOperatedInput.h"
#include "IOperatedOutput.h"
#include "IRegulator.h"

namespace SRCLF {

using IO::IOperatedInput;
using IO::IOperatedOutput;
using Control::IRegulator;

  	/**
	@class Channel
	@brief This class represents abstract "channel" or control loop.
	@detailed Regulation in channel can be enabled or disabled.
	Also control over channel may be "captured" by one of cliets. There are two policies for controlling channel:
	<ul>
		<li>Any client can perform "control command"</li>
		<li>The only client who captured control can perform "control command"</li>
	</ul>
	The channel class contains information about regulation time step and next regulation update time moment.
	*/
	class Channel
	{
		///Is control enabled	  
		bool regulator_enabled;
		///Need capture to control. If true then only client which "captured control" can perform "control"-type commands. Otherwise - any		
		bool need_capture_control;	//If true then only client which "captured control" can perform "control"-type commands. Otherwise - any

		IOperatedInput *operated_input;
		IOperatedOutput *operated_output;
		IRegulator *regulator;

		ptime next_control_moment;
		time_duration control_interval;
	public:
		Channel() : operated_input(NULL), 
			operated_output(NULL), 
			regulator(NULL), 
			regulator_enabled(false), 
			need_capture_control(false) {}

		Channel(IOperatedInput *_operated_input,	
			IOperatedOutput *_operated_output,
			IRegulator *_regulator, 
			bool _regulator_enabled, 
			bool _need_capture_control, 
			double _control_interval, 
			double _time_remains_to_control ) : 
		operated_input(_operated_input), 
			operated_output(_operated_output), 
			regulator(_regulator), 
			regulator_enabled(false), 
			need_capture_control(false) 
		{
			control_interval = milliseconds(1000 * _control_interval);
		}

		~Channel();
		//TODO: Rename to more conventional  setXXX, getXXX
		///Sets "capture control" politics on channel
		void needCaptureControl(bool _need_capture_control) { need_capture_control = _need_capture_control; }
		///Gets "capture control" politics on channel				
		bool needCaptureControl() const { return need_capture_control; }

		///Gets time interval between control events
		const time_duration& getControlInterval() const { return control_interval; }
		///Sets time interval between control events
		void setControlInterval(const time_duration& _control_interval) { control_interval = _control_interval; }

		const ptime& getNextControlTime() const { return next_control_moment; }
		void setNextControlTime(const ptime& _next_control_moment)
		{
			next_control_moment = _next_control_moment;
		}

		///disables regulation in this channel
		void disableRegulator() { regulator_enabled = false; }

		///Sets desired value (setpoint for regulator)
		bool keep(optional<double> value);

		///Update regulation in channel. Input value sent to regulator and then regulator value sent to output
		void update(const ptime&);

		///Gets input object of this channel
		IOperatedInput *getInput() const {return operated_input;};
		void setInput(IOperatedInput* _operated_input) {operated_input = _operated_input;};

		///Gets output object of this channel
		IOperatedOutput *getOutput() const {return operated_output;};
		void setOutput(IOperatedOutput* _operated_output) {operated_output = _operated_output;};

		///Gets regulator object of this channel		
		IRegulator *getRegulator() const {return regulator;};
		void setOutput(IRegulator* _regulator) {regulator = _regulator;};
	};

} //namespace SRCLF

